package cn.shengchao.examstar.ai.domain.service;

import cn.shengchao.examstar.ai.domain.exception.InvalidStudyPlanException;
import cn.shengchao.examstar.ai.domain.model.StudyPlan;
import cn.shengchao.examstar.ai.domain.repository.IAiStudyPlanRepository;
import cn.shengchao.examstar.ai.domain.valueobject.*;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

/**
 * 学习计划领域服务
 * 处理跨聚合的业务逻辑和复杂的业务规则
 * 封装不属于单个聚合的业务逻辑
 */
@Service
@RequiredArgsConstructor
public class StudyPlanDomainService {
    
    private final IAiStudyPlanRepository studyPlanRepository;
    
    /**
     * 创建学习计划
     * 包含业务规则验证
     */
    public StudyPlan createStudyPlan(SpecificationType specificationType,
                                    UserId userId,
                                    DegreeOfMastery degreeOfMastery) {
        
        // 业务规则：检查用户是否可以创建新的学习计划
        if (canUserCreateNewPlan(userId, specificationType)) {
            throw InvalidStudyPlanException.businessRuleViolation(
                "用户已存在该类目的活跃学习计划，无法创建新计划");
        }
        
        // 推荐学习时长和期间
        StudyDuration recommendedDuration = recommendStudyDuration(degreeOfMastery);
        StudyPeriod recommendedPeriod = recommendStudyPeriod(degreeOfMastery, recommendedDuration);
        
        // 生成学习建议
        String studyAdvice = generateStudyAdvice(specificationType, degreeOfMastery);
        
        return StudyPlan.create(
            specificationType,
            userId,
            degreeOfMastery,
            recommendedDuration,
            recommendedPeriod,
            studyAdvice
        );
    }
    
    /**
     * 检查用户是否可以创建新的学习计划
     * 业务规则：每个用户每个类目只能有一个活跃的学习计划
     */
    public boolean canUserCreateNewPlan(UserId userId, SpecificationType specificationType) {
        Optional<StudyPlan> existingPlans = studyPlanRepository.findByUserIdAndSpecificationType(userId, specificationType);
        
        // 检查是否存在活跃状态的学习计划
        return existingPlans.stream()
                .anyMatch(plan -> plan.getStatus().isInProgress() || plan.getStatus() == StudyPlanStatus.DRAFT);
    }
    

    /**
     * 推荐学习时长
     * 根据掌握程度推荐每日学习时长
     */
    public StudyDuration recommendStudyDuration(DegreeOfMastery degreeOfMastery) {
        // 根据掌握程度推荐学习时长的业务逻辑
        return switch (degreeOfMastery.getCode()) {
            case "C" -> StudyDuration.ofMinutes(120L); // 2小时
            case "B" -> StudyDuration.ofMinutes(90L);  // 1.5小时
            case "A" -> StudyDuration.ofMinutes(60L);         // 1小时
            case "S" -> StudyDuration.ofMinutes(30L);            // 0.5小时
            default -> StudyDuration.ofMinutes(60L);                  // 默认1小时
        };
    }

    /**
     * 推荐学习期间
     * 根据掌握程度和每日学习时长推荐学习期间
     */
    public StudyPeriod recommendStudyPeriod(DegreeOfMastery degreeOfMastery, StudyDuration dailyDuration) {
        // 根据掌握程度和每日时长计算推荐的学习天数
        int recommendedDays = calculateRecommendedDays(degreeOfMastery, dailyDuration);
        
        LocalDateTime startTime = LocalDateTime.now();
        LocalDateTime endTime = startTime.plusDays(recommendedDays);
        
        return StudyPeriod.of(startTime, endTime);
    }
    

    /**
     * 计算用户平均完成率
     */
    private double calculateAverageCompletionRate(List<StudyPlan> userHistory) {
        if (userHistory.isEmpty()) {
            return 1.0;
        }
        
        long completedCount = userHistory.stream()
            .mapToLong(plan -> plan.getStatus() == StudyPlanStatus.COMPLETED ? 1 : 0)
            .sum();
        
        return (double) completedCount / userHistory.size();
    }
    
    /**
     * 计算推荐的学习天数
     */
    private int calculateRecommendedDays(DegreeOfMastery degreeOfMastery, StudyDuration dailyDuration) {
        // 基于掌握程度的基础天数
        int baseDays = switch (degreeOfMastery.getCode()) {
            case "C" -> 90; // 3个月
            case "B" -> 60; // 2个月
            case "A" -> 30; // 1个月
            case "S" -> 14; // 2周
            default -> 30;
        };
        
        // 根据每日学习时长调整
        double dailyHours = dailyDuration.getMinutes() / 60.0;
        if (dailyHours >= 2.0) {
            return (int) (baseDays * 0.8); // 减少20%
        } else if (dailyHours <= 0.5) {
            return (int) (baseDays * 1.5); // 增加50%
        }
        
        return baseDays;
    }
    
    /**
     * 生成学习建议
     */
    public String generateStudyAdvice(SpecificationType specificationType, DegreeOfMastery degreeOfMastery) {
        // 根据类目和掌握程度生成个性化的学习建议
        StringBuilder advice = new StringBuilder();
        
        advice.append("针对").append(specificationType.getName()).append("的学习建议：\n");
        
        switch (degreeOfMastery.getCode()) {
            case "NOT_UNDERSTAND" -> {
                advice.append("- 建议从基础概念开始学习\n");
                advice.append("- 多做基础练习题\n");
                advice.append("- 建议寻求老师或同学帮助\n");
            }
            case "LITTLE_UNDERSTAND" -> {
                advice.append("- 重点复习薄弱知识点\n");
                advice.append("- 适量练习提升理解\n");
                advice.append("- 可以尝试讲解给他人听\n");
            }
            case "UNDERSTAND" -> {
                advice.append("- 通过练习巩固知识\n");
                advice.append("- 尝试解决更复杂的问题\n");
                advice.append("- 总结知识点间的联系\n");
            }
            case "MASTER" -> {
                advice.append("- 保持定期复习\n");
                advice.append("- 可以帮助他人学习\n");
                advice.append("- 关注最新发展动态\n");
            }
        }
        
        return advice.toString();
    }
    

    /**
     * 分析用户学习模式并添加个性化建议
     */
    private void analyzeUserLearningPattern(List<StudyPlan> userHistory, StringBuilder advice) {
        // 分析用户的学习完成率
        double completionRate = calculateAverageCompletionRate(userHistory);
        
        advice.append("\n个性化建议：\n");
        
        if (completionRate < 0.5) {
            advice.append("- 建议制定更灵活的学习计划\n");
            advice.append("- 可以将大目标分解为小目标\n");
        } else if (completionRate > 0.8) {
            advice.append("- 您的学习完成率很高，可以尝试更有挑战性的目标\n");
            advice.append("- 考虑增加学习深度或广度\n");
        }
        
        // 分析用户偏好的学习时长
        double avgDuration = userHistory.stream()
            .mapToDouble(plan -> plan.getDailyStudyDuration().getMinutes())
            .average()
            .orElse(60.0);
        
        if (avgDuration < 45) {
            advice.append("- 您偏好短时间学习，建议采用番茄工作法\n");
        } else if (avgDuration > 90) {
            advice.append("- 您能够进行长时间学习，建议注意劳逸结合\n");
        }
    }
}